# -*-coding:utf-8-*-

import json
from datetime import datetime
from pyrestful import mediatypes
from pyrestful.rest import get, put
from pymongo.collection import ReturnDocument
from utils.auth import authenticated
import handlers.base
import tornado
import functools
from handlers.base import Wait


class DevicesStatesHandler(handlers.base.BaseHandler):
    @authenticated
    @get(_path='/api/devices/{device_id}/states', _types=[str], _produces=mediatypes.APPLICATION_JSON)
    def retrieve_device_states(self, device_id):
        if not self.is_owner_of_device(device_id):
            return
        db = self.settings['db']
        devices_states = db.get_collection('devices_states')
        result = devices_states.find_one({'device_id': device_id}, {'_id': 0, 'device_id': 0})
        if result is None:
            result = {}
        self.response_success(result)

    @authenticated
    @put(_path='/api/devices/{device_id}/states', _types=[str],
         _produces=mediatypes.APPLICATION_JSON)
    def update_device_states(self, device_id):
        if not self.is_owner_of_device(device_id):
            return
        self._update_device_states(device_id)
        self.response_success()

    def _on_complete(self, device_id, request_name, request, result):
        if 'power_on_off' != request_name:
            self.response_error('invalid_path')
            return
        if result['result']:
            modification = {request_name: request['flag']}
            db = self.settings['db']
            devices_states = db.get_collection('devices_states')
            devices_states.find_one_and_update({'device_id': device_id}, {'$set': modification}, upsert=True)
        self.finish(result)

    @authenticated
    @tornado.web.asynchronous
    @put(_path='/api/devices/{device_id}/states/{key}', _types=[str],
         _produces=mediatypes.APPLICATION_JSON)
    def update_device_states_by_key(self, device_id, key):
        if not self.is_owner_of_device(device_id):
            return
        if 'power_on_off' != key:
            self.response_error('invalid_path')
            return
        request_name = key
        request = json.loads(self.request.body)
        wait = Wait(functools.partial(self._on_complete, device_id, request_name, request),
                    functools.partial(self.response_error, 'mq_request_timeout'))
        self.mqtornado.rpc_to_device(device_id, request_name, request, wait)

    def _update_device_states(self, device_id):
        db = self.settings['db']
        devices_states = db.get_collection('devices_states')
        modification = json.loads(self.request.body)
        modification['heartbeat'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        devices_states.find_one_and_update({'device_id': device_id}, {'$set': modification}, upsert=True)

    @put(_path='/tmp/api/devices/{device_id}/states', _types=[str],
         _produces=mediatypes.APPLICATION_JSON)
    def tmp_update_device_states(self, device_id):
        self._update_device_states(device_id)
        self.response_success()

    @authenticated
    @get(_path='/api/devices/{device_id}/states/{key}', _types=[str, str], _produces=mediatypes.APPLICATION_JSON)
    def retrieve_device_states_by_key(self, device_id, key):
        if not self.is_owner_of_device(device_id):
            return
        db = self.settings['db']
        devices_states = db.get_collection('devices_states')
        result = devices_states.find_one({'device_id': device_id}, {key: 1})
        if result is None:
            result = {}
        else:
            del result['_id']
        self.response_success(result)

    @authenticated
    @get(_path='/api/devices/{device_id}/states/{array_key}/{array_index}', _types=[str, str, int],
         _produces=mediatypes.APPLICATION_JSON)
    def retrieve_device_states_by_array_key_index(self, device_id, array_key, array_index):
        if not self.is_owner_of_device(device_id):
            return
        db = self.settings['db']
        devices_states = db.get_collection('devices_states')
        # NOTE: set '_id': 1 to filter others not present out, reduce consumption of bandwidth
        result = devices_states.find_one({'device_id': device_id},
                                         {'_id': 1, array_key: {'$slice': [array_index, 1]}})
        if result is None:
            result = {}
        else:
            result = result[array_key][0]
        self.response_success(result)

    @authenticated
    @put(_path='/api/devices/{device_id}/states/{array_key}/{array_index}', _types=[str, str, int],
         _produces=mediatypes.APPLICATION_JSON)
    def update_device_states_by_array_key_index(self, device_id, array_key, array_index):
        if not self.is_owner_of_device(device_id):
            return
        db = self.settings['db']
        devices_states = db.get_collection('devices_states')
        modification = json.loads(self.request.body)
        heartbeat = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        devices_states.find_one_and_update({'device_id': device_id},
                                           {'$set': {'%s.%d' % (array_key, array_index): modification,
                                                     'heartbeat': heartbeat}},
                                           upsert=True,
                                           return_document=ReturnDocument.AFTER)
        self.response_success()
